package xin.config.db;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import xin.core.jpa.naming.CamelImplicitNamingStrategy;
import xin.core.jpa.naming.CamelPhysicalNamingStrategy;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Properties;

/**
 * <pre>
 * Jpa Config
 * </pre>
 *
 * @author lixin_ma@outlook.com
 * @version 1.0
 * @since 2018/7/28 14:38
 */
@Configuration
@EnableTransactionManagement
@EnableAutoConfiguration
@Slf4j
public class JpaConfiguration {

    @Value("${spring.jpa.hibernate.dialect}")
    private String dialect;
    @Value("${spring.jpa.hibernate.format_sql}")
    private String formatSql;
    @Value("${spring.jpa.hibernate.use_sql_comments}")
    private String useSqlComments;

    @Value("${spring.jpa.hibernate.properties.packages-to-scan}")
    private String packagesToScan;

    @Value("${spring.jpa.show-sql}")
    private String showSql;
    @Value("${spring.jpa.hibernate.properties.jdbc.fetch_size}")
    String jdbcFetchSize;
    @Value("${spring.jpa.hibernate.properties.jdbc.batch_size}")
    String jdbcBatchSize;
    @Value("${spring.jpa.hibernate.ddl-auto}")
    private String ddlAuto;
    @Value("${spring.jpa.hibernate.properties.connection.release_mode}")
    private String releaseMode;
    @Value("${spring.jpa.hibernate.properties.connection.autocommit}")
    private String autoCommit;
    @Value("${spring.jpa.hibernate.properties.cache.use_query_cache}")
    private String useQueryCache;
    @Value("${spring.jpa.hibernate.naming.implicit-strategy}")
    private String namingStrategy;
    @Value("${spring.jpa.hibernate.naming.physical-strategy}")
    private String physicalStrategy;

    @Value("${spring.jpa.hibernate.properties.cache.use_second_level_cache}")
    private String useSecondLevelCache;

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        log.info("JpaConfiguration.jpaVendorAdapter init");
        jpaVendorAdapter.setGenerateDdl(true);
        jpaVendorAdapter.setShowSql(true);

        /**
         *
         * 2017-08-10 14:40:09.120  WARN 12056 --- [0.1-8080-exec-1] o.s.orm.jpa.vendor.HibernateJpaDialect   :
         * JDBC Connection to reset not identical to originally prepared Connection
         * - please make sure to use connection release mode ON_CLOSE (the default) and to run against Hibernate 4.2+
         * (or switch HibernateJpaDialect's prepareConnection flag to false
         */
        jpaVendorAdapter.setPrepareConnection(false);
        jpaVendorAdapter.setDatabasePlatform(dialect);
        return jpaVendorAdapter;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) throws SQLException {

        LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
        log.info("JpaConfiguration.entityManagerFactory init");
        lef.setPackagesToScan(packagesToScan);
        lef.setDataSource(dataSource);
        lef.setJpaVendorAdapter(jpaVendorAdapter());

        Properties properties = new Properties();
        properties.setProperty("hibernate.show_sql", showSql);
        properties.setProperty("hibernate.jdbc.fetch_size", jdbcFetchSize);
        properties.setProperty("hibernate.jdbc.batch_size", jdbcBatchSize);
        properties.setProperty("hibernate.hbm2ddl.auto", ddlAuto);
        properties.setProperty("hibernate.format_sql", formatSql);
        properties.setProperty("hibernate.use_sql_comments", useSqlComments);
        properties.setProperty("hibernate.connection.release_mode", releaseMode);
        properties.setProperty("hibernate.connection.autocommit", autoCommit);
        properties.setProperty("hibernate.cache.use_query_cache", useQueryCache);
        properties.setProperty("hibernate.implicit_naming_strategy", namingStrategy);
        properties.setProperty("hibernate.physical_naming_strategy", physicalStrategy);
        properties.setProperty("hibernate.cache.use_second_level_cache",useSecondLevelCache);

        lef.setJpaProperties(properties);
        return lef;
    }

    /**
     *
     * <pre>
     * 说明: Jap的事务 1.5.3 玩法
     * </pre>
     *
     * @return
     * @throws SQLException
     * @author mlx
     * @since 2017年2月15日 下午5:50:01
     */
    @Bean
    public JpaTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactory)
            throws SQLException {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        log.info("JpaConfiguration.transactionManager init");
        transactionManager.setEntityManagerFactory(entityManagerFactory.getObject());
        return transactionManager;
    }

    @Bean
    public CamelPhysicalNamingStrategy getCamelPhysicalNamingStrategy(){
        return new CamelPhysicalNamingStrategy();
    }

    @Bean
    public CamelImplicitNamingStrategy getCamelImplicitNamingStrategy(){
        return new CamelImplicitNamingStrategy();
    }


}
